import numpy as np

from mth import Mth

class OBB:
    def __init__(self, center, axis_x, axis_y, half_extents):
        self.center = center  # 中心点
        self.axis_x = axis_x  # X轴方向
        self.axis_y = axis_y  # Y轴方向
        self.half_extents = half_extents  # 半轴长度

    def __repr__(self):
        return (f"OBB(center={self.center}, axis_x={self.axis_x}, "
                f"axis_y={self.axis_y}, half_extents={self.half_extents})")
    
    def rotate(self, angle):
        """旋转 OBB"""
        self.axis_x = Mth.rotate_vector(self.axis_x, angle)
        self.axis_y = Mth.rotate_vector(self.axis_y, angle)

    def move(self, translation):
        self.center += np.array(translation)

    def get_corners(self):
        """计算 OBB 的四个角点"""
        cx, cy = self.center
        hx, hy = self.half_extents
        ax, ay = self.axis_x
        bx, by = self.axis_y

        # 计算四个角点
        corners = [
            (cx + ax * hx + bx * hy, cy + ay * hx + by * hy),  # 右上角
            (cx + ax * hx - bx * hy, cy + ay * hx - by * hy),  # 右下角
            (cx - ax * hx - bx * hy, cy - ay * hx - by * hy),  # 左下角
            (cx - ax * hx + bx * hy, cy - ay * hx + by * hy)   # 左上角
        ]
        return corners

    @staticmethod
    def calculate_obb(points):
        if len(points) != 4:
            raise ValueError("Exactly 4 points are required to define a 2D OBB.")

        # 将点转换为NumPy数组
        points = np.array(points)

        # 计算中心点
        center = np.mean(points, axis=0)

        # 计算轴向量
        # 使用PCA（主成分分析）来确定主轴方向
        cov_matrix = np.cov(points, rowvar=False)
        eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
        sorted_indices = np.argsort(eigenvalues)[::-1]
        axis_x = eigenvectors[:, sorted_indices[0]]
        axis_y = eigenvectors[:, sorted_indices[1]]

        # 计算半轴长度
        half_extents = np.zeros(2)
        for i, axis in enumerate([axis_x, axis_y]):
            projections = np.dot(points, axis)
            half_extents[i] = (np.max(projections) - np.min(projections)) / 2

        return OBB(center, axis_x, axis_y, half_extents)